package com.zhijian.medical.util;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class BeanUtil {

    private static final Logger logger = LoggerFactory.getLogger(BeanUtil.class);

    /**
     * 是否为空
     *
     * @param obj
     * @return
     */
    public static Boolean isNull(Object obj) {
        return obj == null;
    }

    public static Boolean isNotNull(Object obj) {
        return !isNull(obj);
    }

    /**
     * 是否为空值
     *
     * @param obj
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Boolean isEmpty(Object obj) {
        if (isNull(obj))
            return true;
        if (obj instanceof CharSequence) {
            return ((CharSequence) obj).length() == 0;
        } else if (obj instanceof Collection) {
            return ((Collection) obj).isEmpty();
        } else if (obj instanceof Map) {
            return ((Map) obj).isEmpty();
        } else if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        }
        return false;
    }

    public static Boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    public static boolean isPrimitive(Object obj) {
        return obj.getClass().isPrimitive();
    }

    /**
     * 判断是否原始类型数据（包括String）
     *
     * @param obj
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static boolean isPrimitiveWrapper(Object obj) {
        Class clz = obj.getClass();
        //ignore Void.class
        if (clz.equals(Byte.class) ||
                clz.equals(Short.class) ||
                clz.equals(Integer.class) ||
                clz.equals(Long.class) ||
                clz.equals(Float.class) ||
                clz.equals(Double.class) ||
                clz.equals(BigDecimal.class) ||
                clz.equals(String.class) ||
                clz.equals(Character.class) ||
                clz.equals(Date.class) ||
                clz.equals(Boolean.class) ||

                clz.equals(BigInteger.class) ||

                clz.equals(java.sql.Date.class) ||
                clz.equals(java.sql.Timestamp.class)) {
            return true;
        }
        return false;
    }

    public static boolean isBasicType(Object obj) {
        return isPrimitive(obj) || isPrimitiveWrapper(obj);
    }


    /**
     * 功能描述：将Object对象转化为Map对象
     *
     * @param object
     * @return
     */
    public static Map<String, Object> objToMap(Object object, boolean isSort) {
        Map<String, Object> map = isSort ? new TreeMap<>() : new HashMap<>();
        String propirtes;
        List<Field> list = getFieldNames(object);
        for (Field field : list) {
            propirtes = field.getName();
            Object ro = null;
            try {
                ro = getFieldValue(object, propirtes);
                map.put(propirtes, ro);
            } catch (NoSuchFieldException e) {
                logger.error(e.getMessage(), e);
            }
        }
        return map;
    }

    /**
     * 功能描述：bean转Map<String,Object>，排除不需要转换字段
     *
     * @param
     * @return
     */
    public static Map<String, Object> objToMapExclude(Object object, List<String> fileNames) {
        Map<String, Object> map = new HashMap<String, Object>();
        String propirtes;
        List<Field> list = getFieldNames(object);
        for (Field field : list) {
            propirtes = field.getName();
            if (fileNames != null && fileNames.contains(propirtes))
                continue;
            Object ro = null;
            try {
                ro = getFieldValue(object, propirtes);
                map.put(propirtes, ro);
            } catch (NoSuchFieldException e) {
                logger.error(e.getMessage(), e);
            }
        }
        return map;
    }

    /**
     * 过滤Map字段，排除不需要转换字段
     *
     * @param objectMap
     * @param fileNames
     * @return
     */
    public static Map<String, Object> getMapExclude(Map<String, Object> objectMap, List<String> fileNames) {
        if (fileNames == null || fileNames.isEmpty())
            return objectMap;
        for (String exclude : fileNames) {
            objectMap.keySet().removeIf(s -> s.equals(exclude));
        }
        return objectMap;
    }

    /**
     * map转Object对象
     *
     * @param bean
     * @param map
     */
    public static void mapToObj(Object bean, Map<String, Object> map) {
        String propirtes;
        String methodName;
        Method[] methods = bean.getClass().getDeclaredMethods();
        for (Method method : methods) {
            methodName = method.getName();
            if (method.getName().contains("set") && method.getGenericParameterTypes().length > 0) {
                propirtes = methodName.substring(3);
                propirtes = toLowerString(propirtes);
                if (map.containsKey(propirtes) && map.get(propirtes) != null) {
                    Class<?> type = method.getParameterTypes()[0];
                    Class<?> value = map.get(propirtes).getClass();
                    String typeName = type.getName();
                    String valueName = value.getName();
                    if (typeName.equals(valueName)) {
                        try {
                            bean.getClass().getMethod(methodName, type).invoke(bean, map.get(propirtes));
                        } catch (IllegalAccessException e) {
                            logger.error(e.getMessage(), e);
                        } catch (IllegalArgumentException e) {
                            logger.error(e.getMessage(), e);
                        } catch (InvocationTargetException e) {
                            logger.error(e.getMessage(), e);
                            ;
                        } catch (NoSuchMethodException e) {
                            logger.error(e.getMessage(), e);
                        } catch (SecurityException e) {
                            logger.error(e.getMessage(), e);
                        }
                    }
                }
            }
        }
    }

    /**
     * map转Object对象
     *
     * @param <T>
     * @param cls
     * @param map
     * @return
     */
    public static <T> T mapToObj(Class<T> cls, Map<String, Object> map) {
        if (map == null || map.size() == 0)
            return null;
        return JSON.parseObject(JSON.toJSONString(map), cls);
    }

    /**
     * 首字母最小化
     *
     * @param str
     * @return
     */
    public static String toLowerString(String str) {
        String first = str.substring(0, 1);
        first = first.toLowerCase();
        return first + str.substring(1, str.length());
    }

    /**
     * 功能描述: 获取Object属性值
     *
     * @param object
     * @param propertyName
     * @return
     * @throws NoSuchFieldException
     */
    public static Object getFieldValue(Object object, String propertyName) throws NoSuchFieldException {
        Field field = getFieldName(object.getClass(), propertyName);
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        Object result = null;
        try {
            result = field.get(object);
        } catch (IllegalAccessException e) {
            logger.error("IllegalAccessException:" + e.getMessage(), e);
        }
        field.setAccessible(accessible);
        return result;
    }

    /**
     * 功能描述: 获取Field object
     *
     * @param clazz
     * @param propertyName
     * @return
     * @throws NoSuchFieldException
     */
    public static Field getFieldName(Class<?> clazz, String propertyName) throws NoSuchFieldException {
        for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(propertyName);
            } catch (NoSuchFieldException e) {
                logger.debug("NoSuchFieldException:" + e.getMessage(), e);
            }
        }
        throw new NoSuchFieldException("No such field: " + clazz.getName() + '.' + propertyName);
    }

    /**
     * 获取字段名称
     *
     * @param clazz
     * @return
     */
    public static List<Field> getFieldNames(Object clazz) {
        List<Field> list = new ArrayList<>();
        for (Class<?> superClass = clazz.getClass(); superClass != Object.class; superClass = superClass
                .getSuperclass()) {
            Field[] fields = superClass.getDeclaredFields();
            for (Field field : fields) {
                list.add(field);
            }
        }
        return list;
    }

    /**
     * 字段属性拷贝
     *
     * @param src
     * @param target
     */
    public static void copyPropertiesIgnoreNull(Object src, Object target) {
        BeanUtils.copyProperties(src, target);
    }

    /**
     * 功能描述：从Map取值
     *
     * @param name       目标key
     * @param map        目标map
     * @param defaultStr 取空情况下的默认值
     * @return
     */
    public static String getStr4Map(String name, Map<String, Object> map, String defaultStr) {
        if (map == null || map.get(name) == null || map.get(name).toString().trim().length() == 0)
            return defaultStr;
        return map.get(name).toString();
    }

    /**
     * 功能描述：从Map取值
     *
     * @param name       目标key
     * @param map        目标map
     * @param defaultStr 取空情况下的默认值
     * @return
     */
    public static BigDecimal getDecimal4Map(String name, Map<String, Object> map, BigDecimal defaultStr) {
        if (map == null || map.get(name) == null || map.get(name).toString().trim().length() == 0)
            return defaultStr;
        return new BigDecimal(map.get(name).toString());
    }

    /**
     * 功能描述：从Map取值
     *
     * @param name       目标key
     * @param map        目标map
     * @param defaultStr 取空情况下的默认值
     * @return
     */
    public static Integer getInt4Map(String name, Map<String, Object> map, Integer defaultStr) {
        if (map == null || map.get(name) == null || map.get(name).toString().trim().length() == 0)
            return defaultStr;
        return Integer.valueOf(map.get(name).toString());
    }

    /**
     * 功能描述：从Map取值
     *
     * @param name       目标key
     * @param map        目标map
     * @param defaultStr 取空情况下的默认值
     * @return
     */
    public static Long getLong4Map(String name, Map<String, Object> map, Long defaultStr) {
        if (map == null || map.get(name) == null || map.get(name).toString().trim().length() == 0)
            return defaultStr;
        return Long.valueOf(map.get(name).toString());
    }

    /**
     * 功能描述：从Map取值
     *
     * @param name       目标key
     * @param map        目标map
     * @param defaultStr 取空情况下的默认值
     * @return
     */
    public static Boolean getBoolean4Map(String name, Map<String, Object> map, Boolean defaultStr) {
        if (map == null || map.get(name) == null || map.get(name).toString().trim().length() == 0)
            return defaultStr;
        return Boolean.valueOf(map.get(name).toString());
    }

    /**
     * 功能描述：从Map取值
     *
     * @return
     */
    public static <T> List<T> getList4Map(String name, Map<String, Object> map, List<T> defaultList, Class<T> cls) {
        if (map == null || map.get(name) == null || map.get(name).toString().trim().length() == 0)
            return defaultList;
        return JsonUtil.toArray(map.get(name).toString(), cls);
    }

    /**
     * 求和
     *
     * @param bg1
     * @param bg2
     * @return
     */
    public static BigDecimal add(BigDecimal bg1, BigDecimal bg2) {
        if (bg1 == null)
            bg1 = BigDecimal.ZERO;
        if (bg2 == null)
            bg2 = BigDecimal.ZERO;
        return bg1.add(bg2);
    }

    /**
     * 求差
     *
     * @param bg1
     * @param bg2
     * @return
     */
    public static BigDecimal sub(BigDecimal bg1, BigDecimal bg2) {
        if (bg1 == null)
            bg1 = BigDecimal.ZERO;
        if (bg2 == null)
            bg2 = BigDecimal.ZERO;
        return bg1.subtract(bg2);
    }

    /**
     * 求积
     *
     * @param bg1
     * @param bg2
     * @return
     */
    public static BigDecimal multiply(BigDecimal bg1, Object bg2) {
        if (bg1 == null)
            bg1 = BigDecimal.ZERO;
        if (bg2 == null)
            bg2 = BigDecimal.ZERO;
        return bg1.multiply(new BigDecimal(bg2.toString()));
    }

    /**
     * 除法
     *
     * @param bg1
     * @param bg2
     * @return
     */
    public static BigDecimal divide(BigDecimal bg1, Object bg2) {
        if (bg1 == null)
            bg1 = BigDecimal.ONE;
        if (bg2 == null)
            bg2 = BigDecimal.ONE;
        if (BigDecimal.ZERO.compareTo(new BigDecimal(bg2.toString())) == 0)
            return BigDecimal.ZERO;
        return bg1.divide(new BigDecimal(bg2.toString()), 2, BigDecimal.ROUND_HALF_DOWN);
    }

    /**
     * 将数据转成指定类型数据
     *
     * @param value
     * @param type
     * @return
     */
    public static <T> T convertToType(Object value, Class<T> type) {
        if (isEmpty(value))
            return null;
        String KEY = "KEY";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put(KEY, value);
        return JsonUtil.toRefrenceMap(JsonUtil.toString(map), String.class, type).get(KEY);
    }

    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name", "zsan");
        String s = JsonUtil.toString(map);
        Map<String, Object> map2 = new HashMap<String, Object>();
        map2.put("data", s);
        System.out.println(JsonUtil.toRefrenceMap(JsonUtil.toString(map2), String.class, Map.class).get("data"));
    }
}
